跳到主要内容

ElasticSearch DSL 语句

ES 的 Restful 语法

ES 几种常见的请求方式,与我们的传统的 Restful 有区别

# get请求(获取数据)
http://ip:port/index # 查询 es 的 index
http://ip:port/index/type/doc_id # 根据文档 id 查询指定文档的信息

# post请求
http://ip:port/index/type/_search # 查询文档,可以在请求体中添加 json 字符串的内容,代表查询条件
http://ip:port/index/type/doc_id/_update # 修改文档 ,在请求体中指定 json 字符串,代表修改条件

# put请求
http://ip:port/index # 创建索引,请求体中指定索引的信息
http://ip:port/index/type_mappings # 创建索引,然后指定索引存储文档的属性

# delete请求
http://ip:port/index # 删除索引(删库跑路~)
http://ip:port/index/type/doc_id # 删除指定的文档

field 的类型

前面说了 ES 的 field 和数据库的字段类似,所以它也有类型之分

字符串类型

text           # 最常用,一般用于全文检索,会给 field 分词
keyword # 不会给 field 进行分词(就是关键字,例如地名,人名,手机号之类的)

数值类型

long
integer
short
byte
double
float
half_float # 精度比 float 小一半,float 是 32 位,这个是 16 位
scaled_float # 根据 long 类型的结果和你指定的 secled 来表达浮点类型:long:123 ,secled:100,结果:1.23

时间类型

date         # 可以指定具体的格式  "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"

布尔类型

boolean  # false true

二进制类型

binary       # 基于base64的二进制

范围类型

integer_range # 赋值时,无需指定具体内容,只需存储一个范围即可,指定 gt、lt、gte、lte
double_range
long_range
float_range
data_range
ip_range

经纬度类型

geo_point   # 存储经纬度

ip类型

ip    # v4 v6都可以

操作索引

创建索引

更详细的创建看下面 “创建索引以及 Type” 那一节

// 1 创建名为 parson 的索引
PUT /parson
{
"settings": {
"number_of_shards": 5, // 默认分片为5
"number_of_replicas": 1 // 默认备份为1
}
}

然后可以在 Management 里面找到刚创建的索引

也可以通过 GET 请求来查看索引信息

// 2 查看索引,可以通过图形界面,也可以通过发请求来查看,信息如下:
GET /parson

删除索引

两种方法,一种是直接在 Management 里面找到这个索引选中删除,另一种则是使用 DELETE 请求

DELETE /parson

获取所有索引库信息

GET _cat/indices?v

创建索引以及 Type

分片(shard):因为 ES 是个分布式的搜索引擎,所以索引通常都会分解成不同部分,而这些分布在不同节点的数据就是分片。ES自动管理和组织分片, 并在必要的时候对分片数据进行再平衡分配,所以用户基本上不用担心分片的处理细节,一个分片默认最大文档数量是 20亿。

Integer.MAX_VALUE - 128 = 2,147,483,519

副本(replica):ES默认为一个索引创建5个主分片, 并分别为其创建一个副本分片. 也就是说每个索引都由5个主分片成本, 而每个主分片都相应的有一个copy.

PUT /book
{
"settings": {
"number_of_shards": 5, // 分片数(默认 5)
"number_of_replicas": 1 // 备份分片数目(默认 1)
},
"mappings": { // 指定数据结构
"novel":{ // 指定索引 Type 为 novel
"properties":{ // 文档存储的 field
"name":{ // 属性名
"type": "text", // 属性的类型
"analyzer": "ik_max_word", // 使用 ik 分词器
"index": true, // 当前 field 可以作为查询条件
"store": false // 是否需要额外的存储
},
"author":{
"type": "keyword"
},
"count":{ // 价格
"type": "long"
},
"onSale":{ // 图书的上架时间
"type": "date",
// 写入多种格式,每种格式都会依次尝试转换,直到有匹配的为止
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" // 三种格式都可以
},
"descr": { // 说明
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
}

案例二:这里创建了两个 type:people、transactions

{
"data": {
"mappings": {
"people": {
"properties": {
"name": {
"type": "string",
},
"address": {
"type": "string"
}
}
},
"transactions": {
"properties": {
"timestamp": {
"type": "date",
"format": "strict_date_optional_time"
},
"message": {
"type": "string"
}
}
}
}
}
}

文档的操作

添加文档

文档以 _index_type_id,三个内容来确定唯一的一个文档(唯一标识)

自动生成 ID 的方式:

POST /book/novel
{
"name": "三体",
"author": "刘慈欣",
"count": 100000,
"on-sale": "2010-01-01",
"descr": "这是一部硬科幻小说~"
}

执行后可以发现它自动生成了这个 id

不过这样的 id 不好记(如上图所示的 _id),所以一般都是手动指定

PUT /book/novel/1   // 注意这里是 PUT 后面跟着一个 id
{
"name": "矛盾论",
"author": "毛泽东",
"count": 20000,
"on-sale": "1935-01-01",
"descr": "毛泽东的书~"
}

生成的结果如下:

修改文档

覆盖式修改 PUT 请求

PUT /book/novel/1   // 也就是我们指定id添加的那个,如果重复执行会将老的覆盖
{
"name": "矛盾论",
"author": "毛泽东",
"count": 20000,
"on-sale": "1935-01-01",
"descr": "矛盾是什么等等"
}

doc 修改字段 POST 请求

POST /book/novel/2/_update
{
// 这个 doc 是固定的
"doc": { // 里面指定要修改的键值
"name": "时间移民"
}
}

查看文档

要看到全部数据可以通过 Management 里的

然后一步步的填写

再回到 Discover 就可以看到数据了

删除文档

DELETE /book/novel/szANLXYBuLPYwN8oa5RL    # 根据索引类型id确定到doc然后删除

Sort 排序

// 搜索排序
GET /user/_search
{
"query": {
"match_all": {}
},
"sort": {
"age": {
"order": "desc" # asc升序 desc 降序
}
}
}

分页查询

GET /user/_search
{
"query": {
"match_all": {}
},
"sort": {
"age": {
"order": "desc"
}
},
"from": 0,
"size": 2
}

from 是从 N 的记录开始查询 size 每页显示条数

关键词查询

普通查询 match

# match会对搜索词进行分词,然后对分词后的结果进行搜索
GET _search
{
"query": {
"match": {
字段名: 搜索词
}
}
}

例如

GET /topics/_search 
{
"query": {
"match": {
"name": "张三"
}
}
}

我们使用 match 和默认分词器,会把张三进行分词,分成张、三、张三进行检索 会匹配到的结果有

张三
张三丰
张飞
三德子
张二丰
马三丰

多个字段搜索 multi_match

# multi_match 查询允许你做match查询的基础上同时搜索多个字段
GET _search
{
"query": {
"multi_match": {
"query": 搜索词,
"fields": [
字段1,
字段2
……
]
}
}
}

精确查询 term

# term 是精确查询,查询过程中不会对搜索词进行分词,所以搜索词必须是文档分词集合中的一个
GET _search # 查询所有索引中的数据
或者 GET index_name/_search # 查询一个索引下的所有数据
或者 GET index_name/type_name/_search # 查询一个索引下的一个Type下的所有数据
{
"query":{
"term":{
字段名:搜索词
}
}
}


# terms 允许多个Term,也不会分词
{
"query":{
"terms":{
字段名:
[
字段值1,
字段值2
]
}
}
}

前缀匹配查询 prefix

#  prefix:前缀匹配,所有以特定搜索词开头的内容
GET _search
{
"query": {
"prefix": {
字段名 : 搜索词
}
}
}

模糊查询 fuzzy

GET /topics/_search
{
"query": {
"fuzzy": {
"title": "weather"
}
}
}

使用 fuzzy 就像百度一样,你输入个 “邓子棋”,也能把 “邓紫棋” 查出来,有一定的纠错能力 加 .keyword 是要匹配完整的词

GET /topics/_search 
'{
"query": {
"fuzzy": {
"name.keyword": "张三"
}
}
}

会匹配到的结果有

张三
张三丰
张飞
张二丰
马三丰

通配符查询 wildcard

GET /topics/_search 
{
"query": {
"wildcard": {
"name.keyword": "张三*"
}
}
}

使用 wildcard 相当于 SQL 的 like,前后都可以拼接 *,表示匹配 0 到多个任意字符加 .keyword 是要匹配完整的词,会匹配到的结果有

张三
张三丰

过滤查询

多字段查询(组合查询)

这时就应该使用组合查询:bool 查询

must 子句:文档必须匹配 must 查询条件(AND); should 子句:文档应该匹配 should 子句查询的一个或多个(OR); must_not 子句:文档不能匹配该查询条件(NOT); filter 子句:过滤器,文档必须匹配该过滤条件,跟must子句的唯一区别是,filter不影响查询的score;

GET /topics/_search
{
"query": {
"bool": {
"should": [
{ "match": { "title": "hometown" } },
{ "match": { "content": "hometown" } }
]
}
}
}

也可以写成

GET /topics/_search
{
"query": {
"bool": {
"should": [
{
"multi_match": {
"query": "hometown",
"fields": ["title", "content"]
}
}
]
}
}
}

范围搜索 range

#过滤-range 范围过滤
#gt表示> gte表示=>
#lt表示< lte表示<=
GET _search
{
"query":{
"range": {
字段名: {
"gte": 30,
"lte": 57
}
}
}
}

查询哪些数据包含某个字段

exists

GET _search
{
"query": {
"exists":{
"field": 要查询的字段名
}
}
}

合并查询


GET _search
{
"query": {
"bool": {
must/must_not/should: [
{
"term"……
},
{
"range"……
}
……
]
}
}
}